/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package makao.server;

import java.awt.Color;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import shared.Card;
import shared.MakaoPackage;
import shared.ThrowCards;

/**
 *
 * @author latata_2
 */
public class Server extends Thread {

    public static final int STATE_SERVER_STOPPED = 0;
    public static final int STATE_SERVER_STARTED = 1;
    public static final int STATE_GAME_STARTED = 2;
    public static final int STATE_GAME_FINISHED = 3;
    //public static final int STATE_GAME_ = 0;
    private ServerView serverView = null;
    private boolean serverStop = true;
    private ServerSocket serverSocket = null;
    private int port = 9753;
    private Game game;
    private ArrayList<Player> players;
    private int serverState = 0;
    public ArrayList<PlayerConnection> playerConnections;
    public SendPackageController sendPackageController;

    public void sendToAll(MakaoPackage o) {
        //int i = 0;
        for (PlayerConnection playerConnection : playerConnections) {
            playerConnection.send(o);
            //i++;
        }
    }

    public void removePlayer(PlayerConnection playerConnection) {
        boolean playerRemoved = false;
        for (int i = 0; i < players.size() && !playerRemoved; i++) {
            if (players.get(i).getPlayerConnection() == playerConnection) {
                players.remove(i);
            }
        }
        playerConnections.remove(playerConnection);
        if (players.size() < 2) {
            serverView.getStartGameButton().setEnabled(false);
            if (serverState == STATE_GAME_STARTED) {
                sendPackageController.sendMessgae2All("Error", "Nie można dokończyć gry.");
            }
        }
    }

    public Server() {
        serverView = new ServerView(this);
        serverView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        serverView.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosed(WindowEvent e) {
                if (!serverStop) {
                    setServerStop();
                }
            }
        });
        serverView.setVisible(true);
        playerConnections = new ArrayList<PlayerConnection>();
        sendPackageController = new SendPackageController(this);


    }

    public ArrayList<Player> getPlayers() {
        return players;
    }

    @Override
    public void run() {
        setServerState(STATE_SERVER_STARTED);
        try {
            serverSocket = new ServerSocket(port);
            players = new ArrayList<Player>();
            addLog("Uruchomiono serwer.", Color.red);
            serverStop = false;
            while (!serverStop) {
                try {
                    Socket connection = serverSocket.accept();
                    PlayerConnection playerConn = new PlayerConnection(this, connection, playerConnections.size());
                    playerConnections.add(playerConn);
                    playerConn.start();
                } catch (IOException ex) {
                    System.out.println("Serwer został zatrzymany.");
                    serverStop = true;
                }
            }
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(serverView, "Wystąpił błąd podczas tworzenia serwera.");
        }
    }

    public void setServerStop() {
        setServerState(STATE_SERVER_STOPPED);
        this.serverStop = true;
        try {
            serverSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        serverView.dispose();
    }

    public void setServerState(int serverState) {
        this.serverState = serverState;
    }

    public int getServerState() {
        return serverState;
    }

    public void startGame() {
        game = new Game(this, players);
        serverState = STATE_GAME_STARTED;
        //game.setServer(this);

    }

    public void addLog(String log, Color color) {
        String red = Integer.toHexString(color.getRed());
        String green = Integer.toHexString(color.getGreen());
        if (green.length() == 1) {
            green = "0" + green;
        }
        String blue = Integer.toHexString(color.getBlue());
        if (blue.length() == 1) {
            blue = "0" + blue;
        }
        String colorHex = red + green + blue;
        //System.out.println(serverView.getjEditorPane1().getText());
        serverView.getjEditorPane1().setText("\n" + log);
    }

    public void newPlayerLogin(PlayerConnection playerConnection, String login) {
        if (serverState == STATE_SERVER_STARTED) {
            boolean alreadyExists = false;
            boolean alreadyLoggedIn = false;
            for (Player p : players) {
                if (p.getPlayerName().equals(login)) {
                    alreadyExists = true;
                }
                if (p.getPlayerConnection() == playerConnection) {
                    alreadyLoggedIn = true;
                }
            }
            if (!alreadyExists && !alreadyLoggedIn) {
                Player newPlayer = new Player(login, playerConnection);
                players.add(newPlayer);
                if (players.size() > 1) {
                    serverView.getStartGameButton().setEnabled(true);
                }
                sendPackageController.sendLoginConfirmation(playerConnection);
                addLog("Dołączył " + login, Color.yellow);
            } else if (alreadyExists) {
                sendPackageController.sendLoginFailed(playerConnection, "Login zajęty.");
            } else if (alreadyLoggedIn) {
                sendPackageController.sendLoginFailed(playerConnection, "Jesteś już zalogowany.");
            }
        } else {
            sendPackageController.sendLoginFailed(playerConnection, "Logowanie niemożliwe.");
        }
    }

    public void throwCards(PlayerConnection playerConnection, ThrowCards thorwCards) {
        try {
            boolean error = false;
            for (Card card : thorwCards.getThrownCards()) {
                if (card.getType() == Card.JOKER && card.getAsJoker() == null) {
                    error = true;
                }
            }
            if (!error) {
                game.throwCards(getPlayer(playerConnection), thorwCards);
                if (serverState != STATE_SERVER_STARTED) {
                    sendPackageController.sendGameInfo();
                }
            } else {
                sendPackageController.sendMessgae(playerConnection, "Error", "Joker musi miec przypisaną imitacje.");
            }
        } catch (Exception e) {
            sendPackageController.sendMessgae(playerConnection, "Error", e.getMessage());
        }
    }

    public void getCards(PlayerConnection playerConnection) {
        try {
            game.giveCardsToPlayer(getPlayer(playerConnection));
            sendPackageController.sendGameInfo();
        } catch (Exception e) {
            sendPackageController.sendMessgae(playerConnection, "Error", e.getMessage());
        }
    }

    public void waitTurns(PlayerConnection playerConnection) {
        try {
            game.waitTurns(getPlayer(playerConnection));
            sendPackageController.sendGameInfo();
        } catch (Exception e) {
            sendPackageController.sendMessgae(playerConnection, "Error", e.getMessage());
        }
    }

    private Player getPlayer(PlayerConnection playerConnection) {
        for (Player player : players) {
            if (player.getPlayerConnection() == playerConnection) {
                return player;
            }
        }
        return null;
    }

    public Game getGame() {
        return game;
    }

    public void gameFinished(Player winner) {
        winner.updatePoints(-50);
        for (Player player : players) {
            if (player != winner) {
                int points = 0;
                for (Card card : player.getCards()) {
                    switch (card.getType()) {
                        case Card.TWO:
                            points += 2;
                            break;
                        case Card.THREE:
                            points += 3;
                            break;
                        case Card.FOUR:
                            points += 4;
                            break;
                        case Card.FIVE:
                            points += 5;
                            break;
                        case Card.SIX:
                            points += 6;
                            break;
                        case Card.SEVEN:
                            points += 7;
                            break;
                        case Card.EIGHT:
                            points += 8;
                            break;
                        case Card.NINE:
                            points += 9;
                            break;
                        case Card.JOKER:
                            points += 50;
                            break;
                        default:
                            points += 10;
                            break;
                    }
                }
                player.updatePoints(points);
            }
        }
        sendPackageController.sendMessgae2All("Gra zakończona!", winner.getPlayerName());
        serverState = STATE_SERVER_STARTED;
        this.serverView.getStartGameButton().setEnabled(true);
    }
}
